/** \file Actions.cpp
 *  \author Adrian Schweizer
 *  \created  $Sa 06 Okt 02:38:52 pm CEST 2007 schwadri@SchwadriLaptop$
 *  \modified $Mo 21 Jan 11:58:35 am CET 2008 schwadri@SchwadriLaptop.local$
 */

#include "Actions.hpp"
#include "GameController.hpp"
#include "TeamManager.hpp"

#include "../network/NetworkController.hpp"

using namespace game;
using namespace game::action;

//===============================================================================
///Actions
//===============================================================================

bool GameActionBase::ValidateOrigin(GameController& gc, network::Client::Id origin, network::Client::Id sender) const
{
    //1. check that we are inside the range of possibly valid ids:
    //FIXME:
    if(origin < 0 || sender < 0) //origin >= gc.Network().client_size())
        return false;

    //FIXME:2. check whether the client ids are valid
    /*if(!gc.Network().IsValid(origin) || !gc.Network().IsValid(sender))
        return false;*/

    //3. check whether the sender is allowed to send actions that come from origin
    if(sender != network::Client::SERVER && origin != sender)
        return false;

    return true;
}


//Change Client Name
//...............................................................................

ClientChangeName::ClientChangeName()
:   m_cid(network::Client::INVALID)
{ }

ClientChangeName::ClientChangeName(network::Client::Id origin, const std::string& name, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r),
    m_cid(origin),
    m_name(name)
{ }

bool ClientChangeName::Validate(GameController& gc, network::Client::Id sender) const
{
    //validate clientid
    if(!ValidateOrigin(gc,m_cid,sender))
        return false;
    //validate supplied name
    if(m_name.size() > GameController::LIMIT_CLIENT_NAME_SIZE)
        return false;
    //TODO: check for invalid characters?
    return true;
}

bool ClientChangeName::Execute(GameController& gc, network::Client::Id sender) const
{
    //execute
    //FIXME:gc.Network().Clients()[m_cid].Name(m_name);
    return true;
}

//Client Change Team
//...............................................................................

ClientChangeTeam::ClientChangeTeam()
{ }

ClientChangeTeam::ClientChangeTeam(network::Client::Id origin, char new_team, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r),
    m_cid(origin),
    m_teamid(new_team)
{ }

bool ClientChangeTeam::Validate(GameController& gc, network::Client::Id sender) const
{
    //validate clientid
    if(!ValidateOrigin(gc,m_cid,sender))
        return false;

    if(!ValidateTeamId(gc,m_teamid))
        return false;

    return true;
}

bool ClientChangeTeam::ValidateTeamId(GameController& gc,char teamid) const
{
    //validate teamid range
    if((m_teamid<0&&teamid!=-1) || m_teamid >gc.Teams().NumberOfTeams())
        return false;

    //validate that the team has at least one open player slot left
    Team & team = gc.Teams()[m_teamid];
    if(team.AvailablePlayerSlots() < 1)
        return false;

    return true;
}

bool ClientChangeTeam::Execute(GameController& gc, network::Client::Id sender) const
{
    network::Client::Id cid=m_cid;

    if(gc.Network().IsServer())
        cid=sender;

    TeamManager & tm = gc.Teams();
    Player::Id  pid =   tm.PlayerFromClient(cid);
    //only apply changes if the team is not the same as before (or he is entering a team the first time)
    if(pid.team != m_teamid || !pid.Valid())
    {
        bool unready_all=true;
        if(pid.Valid())
            //this client is already a player->Remove the old entry
            tm[pid.team].Remove(pid);
        else if(pid.team==-1 && pid.player >-1)
            //the client is a spectator
            tm.Spectators().Remove(pid);


        if(m_teamid==-1)
        {
            //become spectator
            tm.Spectators().PushBack(cid);
            //check if the player just joined. because he becomes a spec we don't want to unready all the players
            if(pid.team==-1)
                unready_all=false;
        }
        else
            tm[m_teamid].PushBack(cid);

        //unready all players
        if(unready_all)
        {
            SetPlayerReadyVisitor   unready(false);
            unready.Visit(gc.Teams());
            //gc.CancelCountDown();
        }
        return true;
    }
    return false;
}


PlayerReady::PlayerReady()
{ }

PlayerReady::PlayerReady(Player::Id pid, int ticks, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r)
{ }

bool PlayerReady::Validate(GameController& gc, network::Client::Id sender) const
{
    return false;
}

bool PlayerReady::Execute(GameController& gc, network::Client::Id sender)
{
    return false;
}

GameChangeOptions::GameChangeOptions()
{ }

GameChangeOptions::GameChangeOptions(const GameOptions& go, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r)
{ }

bool GameChangeOptions::Validate(GameController& gc, network::Client::Id sender) const
{
    return false;
}

bool GameChangeOptions::Execute(GameController& gc, network::Client::Id sender) const
{
    return false;
}

GameChangeName::GameChangeName()
{ }

GameChangeName::GameChangeName(const std::string& name, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r)
{ }

bool GameChangeName::Validate(GameController& gc, network::Client::Id sender) const
{
    return false;
}

bool GameChangeName::Execute(GameController& gc, network::Client::Id sender) const
{
    return false;
}

TeamChangeName::TeamChangeName()
{ }

TeamChangeName::TeamChangeName(char teamid, const std::string& name, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r)
{ }

bool TeamChangeName::Validate(GameController& gc, network::Client::Id sender) const
{
    return false;
}

bool TeamChangeName::Execute(GameController& gc, network::Client::Id sender) const
{
    return false;
}

TeamChangeOpenSlots::TeamChangeOpenSlots()
{ }

TeamChangeOpenSlots::TeamChangeOpenSlots(char teamid, char open_slots, const receiver_mask& r /*= receiver_mask()*/)
:   GameActionBase(r)
{ }

bool TeamChangeOpenSlots::Validate(GameController& gc, network::Client::Id sender) const
{
    return false;
}

bool TeamChangeOpenSlots::Execute(GameController& gc, network::Client::Id sender) const
{
    return false;
}

//Show Chat Message
//...............................................................................
